using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
using Microsoft.TeamFoundation;
using Microsoft.TeamFoundation.VersionControl.Common;
using Microsoft.TeamFoundation.Build.Proxy;
using System.Collections;
using System.Xml;
using System.IO;

namespace ManageBuildData
{
    public class TfsDataClient
    {
        TeamFoundationServer tfs;
        WorkItemStore ws;
        VersionControlServer tfvc;
        IBuildServer bs;
        string project;
        IBuildDetail[] builds;
        IBuildDetail build;
        string SelectedBuildType;
        IQueuedBuild QueuedBuild;
        List<int> changeSets = null;

        public void init(string Tfs, string Project)
        {
            tfs = this.GetTFS(Tfs);
            project = this.GetTeamProject(Project);
        }
        private TeamFoundationServer GetTFS(string Tfs)
        {
            TeamFoundationServer _tfs = TeamFoundationServerFactory.GetServer(Tfs);
            tfvc = (VersionControlServer)_tfs.GetService(typeof(VersionControlServer));
            return _tfs;
        }
        private string GetTeamProject(string teamProject)
        {
            ws = (WorkItemStore)tfs.GetService(typeof(WorkItemStore));
            Project _project = ws.Projects[teamProject];
            return _project.Name; ;
        }
        public string[] GetBuildTypes()
        {
            bs = (IBuildServer)tfs.GetService(typeof(IBuildServer));
            IBuildDefinition[] BuildDefinitions = bs.QueryBuildDefinitions(project);
            List<string> buildDefNames = new List<string>();
            buildDefNames.Add("Select Build Definition");
            foreach (IBuildDefinition BuildDefinition in BuildDefinitions)
            {
                buildDefNames.Add(BuildDefinition.Name);
            }
            return buildDefNames.ToArray();
        }

        public string[] GetBuilds(string BuildType)
        {
            SelectedBuildType = BuildType;
            builds = bs.QueryBuilds(project, BuildType);
            List<string> buildLabelName = new List<string>();
            for (int i=0;i<builds.Length;i++)
            {
                buildLabelName.Add(builds[i].BuildNumber);
            }
            return buildLabelName.ToArray();            
        }

        public List<int> GetChangesetNumbers(string buildNumber)
        {
            foreach (IBuildDetail buildDetail in builds)
            {
                if (buildDetail.BuildNumber == buildNumber)
                {
                    build = buildDetail;
                    break;
                }
            }
            List<IChangesetSummary> AssociatedChangesets = InformationNodeConverters.GetAssociatedChangesets(build);
            if (AssociatedChangesets.Count == 0)
            {
                throw new Exception("This build does not have any changesets and workitems associated");
            }
            List<int> ChangeSets = new List<int>();

            foreach (IChangesetSummary changeSet in AssociatedChangesets)
            {               
                ChangeSets.Add(changeSet.ChangesetId);                
            }
            return ChangeSets;
        }

        public List<int> GetChangeSetsAfterBuild(string buildNumber)
        {
            List<int> AssociatedChangeSets = null;
            try
            {
                AssociatedChangeSets = removeDuplicates(this.GetChangesetNumbers(buildNumber));
                //GetChangeSetNumbers return all the changesets considered for that build
                AssociatedChangeSets.Sort();
            }
            catch(Exception ex)
            {
                throw new Exception(ex.Message);
            }
            int LastChangeSet = 0;
            foreach (int changeSet in AssociatedChangeSets)
            {
                if (changeSet > LastChangeSet)
                {
                    LastChangeSet = changeSet;
                }
            }
            List<int> ChangeSetsAfterSelectedBuild = new List<int>();
            int LastChangeSetInTFVC = tfvc.GetLatestChangesetId();
            for (int i = LastChangeSet + 1; i <= LastChangeSetInTFVC; i++)
            {
                try
                {
                    Changeset changeset = tfvc.GetChangeset(i);
                    if (changeset.Comment != "Label Change")
                    {
                        ChangeSetsAfterSelectedBuild.Add(changeset.ChangesetId);
                    }
                }
                catch
                {
                }
            }
            return ChangeSetsAfterSelectedBuild;
        }
        public List<string> GetChangeSetComments(List<int> ChangeSetIds)
        {
            List<string> ChangeSetComments = new List<string>();
            foreach (int ChangeSetId in ChangeSetIds)
            {
                ChangeSetComments.Add(tfvc.GetChangeset(ChangeSetId).Comment);
            }
            return ChangeSetComments;
        }
        static List<int> removeDuplicates(List<int> inputList)
        {
            Dictionary<int, int> uniqueStore = new Dictionary<int, int>();
            List<int> finalList = new List<int>();

            foreach (int currValue in inputList)
            {
                if (!uniqueStore.ContainsKey(currValue))
                {
                    uniqueStore.Add(currValue, 0);
                    finalList.Add(currValue);
                }
            }
            return finalList;
        }
        

        //SetLabel method gets the set of changesets which were associated with selected build 
        // and the changesets which were selected by the user and sets a temporary label to all of them.
        public void SetLabel(List<int> ichangeSets, string LabelName, string SelectedBuild)
        {
            //First get changesets for the build
            //for that create an array of items labeled with selected build number
            LabelVersionSpec LabelSpec = new LabelVersionSpec(SelectedBuild);            
            ItemSet LabeledItems =  tfvc.GetItems("$/" + project, LabelSpec, RecursionType.Full);
            Item[] items = LabeledItems.Items;
            
            // Now add the latest changeset associated with each item
            List<int> csInBuild = new List<int>();
            foreach (Item item in items)
            {
                csInBuild.Add(item.ChangesetId);
            }

            //now add changeset numbers passed by parameter ichangesets and remove duplicates if any and sort them
            foreach (int cs in ichangeSets)
            {
                csInBuild.Add(cs);
            }
            changeSets = removeDuplicates(csInBuild);
            changeSets.Sort();
            //Create a versioncontrol object
            VersionControlLabel labelToCreate = new VersionControlLabel(tfvc, LabelName, tfvc.AuthenticatedUser, "$/" + project, "Demo Label");
            //Create labeled items. Remove items which are for build configuration files
            List<LabelItemSpec> labelItemsSpecs = new List<LabelItemSpec>();
            for (int i = 0; i < changeSets.Count; i++)
            {
                foreach (Change change in tfvc.GetChangeset(changeSets[i]).Changes)
                {
                    if (!change.Item.ServerItem.Contains("TeamBuildTypes"))
                    {
                        ItemSpec changeSetItemSpec = new ItemSpec(change.Item.ServerItem, RecursionType.Full);
                        labelItemsSpecs.Add(new LabelItemSpec(changeSetItemSpec, new ChangesetVersionSpec(changeSets[i]), false));
                    }
                }
                

            }
            //Now actually label the items. Remove the exisitng label if any.
            try
            {
                LabelResult[] PrevResults = tfvc.DeleteLabel(LabelName, "$/" + project);
            }
            catch
            {
            }
            LabelResult[] results = tfvc.CreateLabel(labelToCreate, labelItemsSpecs.ToArray(), LabelChildOption.Replace);
            
           
        }
        
        public bool ModifyTfsBuildProj(string label, string SelectedBuild)
        {
            try
            {
                List<Changeset> changeSetList = new List<Changeset>();
                foreach(int cs in changeSets)
                {
                    changeSetList.Add(tfvc.GetChangeset(cs));
                }
                //Get the build defiition object
                IBuildDefinition buildDef = bs.GetBuildDefinition(project, SelectedBuildType);
                
                //Create a build request object
                IBuildRequest request = buildDef.CreateBuildRequest();
                // Specify that we want to get labeled version
                request.GetOption = GetOption.Custom;
                request.CustomGetVersion = "LDemo";
                //Put the build in queue
                QueuedBuild = bs.QueueBuild(request);
                // Get the details object of the queued build so that we can associate changesets to it.
                build = QueuedBuild.Build;               
                //Specify that we want to associate non-default changesets
                InformationNodeConverters.AddAssociatedChangesets(build, changeSetList.ToArray());
                
                timer = new System.Timers.Timer(5000);
                
                timer.Elapsed +=new System.Timers.ElapsedEventHandler(timer_Elapsed);
                timer.Start();
                
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
            
        
        }
        //string buildUri;
        System.Timers.Timer timer;
        void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (QueuedBuild.Status == QueueStatus.Completed || QueuedBuild.Status == QueueStatus.Canceled || QueuedBuild.Status == QueueStatus.Postponed)
            {
                timer.Stop();
                BuildCompleted(this, EventArgs.Empty);
            }
            
            //Following code is deprecated and meant for TFS 2005
            //BuildData bd = buildStore.GetBuildDetails(buildUri);
            //if (bd.BuildStatus == "Successfully Completed" || bd.BuildStatus == "Failed")
            //{
            //    timer.Stop();
            //    BuildCompleted(this, EventArgs.Empty);
                
            //}
        }
        public event EventHandler BuildCompleted;

        public void DeleLabel()
        {
            tfvc.DeleteLabel("Demo", "$/" + project);
            
        }
        
    }
}
